package cn.hutool.core.util;

import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 代码执行辅助工具
 * 减少代码中try catch的使用频率，让代码可读性更强，更美观
 *
 * @author zhangkaiyong
 */
public class ExecUtil {

	private final static Logger log = Logger.getLogger(ExecUtil.class.getName());

	/**
	 * 打印日志
	 */
	public static void log(String message, Exception e, Level level) {
		if (null == level) {
			return;
		}
		log.log(level, message, e);
	}

	// ===================== 无返回值 START =====================

	@FunctionalInterface
	public interface Executable {
		void exec() throws Exception;
	}

	/**
	 * 忽略异常执行指定方法，无返回值
	 *
	 * @param exec     待执行的方法
	 * @param level    日志级别
	 * @param callback 异常回调
	 */
	public static void tryExec(Executable exec, Level level, Consumer<Exception> callback) {
		try {
			exec.exec();
		} catch (Exception e) {
			log("Exception occurred while executing(will be ignored)", e, level);
			if (Objects.nonNull(callback)) {
				callback.accept(e);
			}
		}
	}

	/**
	 * 忽略异常执行指定方法，无返回值
	 */
	public static void tryExec(Executable exec, Level level) {
		tryExec(exec, level, null);
	}

	/**
	 * 忽略异常执行指定方法，无返回值
	 * 支持对异常进行消费
	 */
	public static void tryExec(Executable exec, Consumer<Exception> callback) {
		tryExec(exec, Level.WARNING, callback);
	}

	/**
	 * 忽略异常执行指定方法，无返回值
	 */
	public static void tryExec(Executable exec) {
		tryExec(exec, Level.WARNING, null);
	}
	// ===================== 无返回值 END =====================

	// ===================== 有返回值 START ===================
	@FunctionalInterface
	public interface Callable<R> {
		R call() throws Exception;
	}

	/**
	 * 忽略异常执行指定方法，有返回值
	 *
	 * @param exec     待执行方法
	 * @param level    日志级别
	 * @param callback 异常回调
	 * @param <R>      返回值泛型
	 * @return R
	 */
	public static <R> R tryCall(Callable<R> exec, Level level, Function<Exception, R> callback) {
		try {
			return exec.call();
		} catch (Exception e) {
			log("Exception occurred while executing(will be ignored)", e, level);
			return Optional.ofNullable(callback).map(c -> c.apply(e)).orElse(null);
		}
	}

	/**
	 * 忽略异常执行指定方法，有返回值
	 */
	public static <R> R tryCall(Callable<R> exec, Level level) {
		return tryCall(exec, level, null);
	}

	/**
	 * 忽略异常执行指定方法，有返回值
	 * 支持对异常进行消费
	 */
	public static <R> R tryCall(Callable<R> exec, Function<Exception, R> callback) {
		return tryCall(exec, Level.WARNING, callback);
	}

	/**
	 * 忽略异常执行指定方法，有返回值
	 */
	public static <R> R tryCall(Callable<R> exec) {
		return tryCall(exec, Level.WARNING, null);
	}
	// ===================== 有返回值 END =====================
}
